﻿using System.ComponentModel;
using BalanceManager.Model;
using BalanceManager.Services;
using BalanceManager.ViewModels;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System.Collections.Generic;

namespace UnitTests.ViewModelTests
{
    [TestClass]
    public class AddFundFlowViewModelTests
    {
        [TestMethod]
        public void ActivatesWithParamsOnlyNewInstance()
        {
            var currentFundFlowChangesCount = 0;
            var dataServiceMock = new Mock<IDataService>();
            var firstParam = new FundFlowEditableParameter() {EditingMode = false, FundFlow = new FundFlow(FlowType.Expense)};
            var secondParam = new FundFlowEditableParameter() {EditingMode = true, FundFlow = new FundFlow(FlowType.Profit)};
            var firstDict = new Dictionary<string, object>() { { "fundFlowParam", firstParam } };
            var secondDict = new Dictionary<string, object>() { {"fundFlowParam", secondParam} };
            var viewModel = new AddFundFlowViewModel(dataServiceMock.Object);

            viewModel.PropertyChanged += (sender, args) =>
            {
                if (args.PropertyName == "CurrentFundFlow")
                    ++currentFundFlowChangesCount;
            };
            // must accept parameters from only first dictionary
            viewModel.Activate(firstDict);
            // second call
            viewModel.Activate(secondDict);

            Assert.AreEqual(firstParam.FundFlow, viewModel.CurrentFundFlow);
            Assert.AreEqual(1, currentFundFlowChangesCount);
        }

        [TestMethod]
        public void RecentlyItemUpdateCommandUpdatesCurrentFundFlowItemId()
        {
            var currentFundFlowChanged = false;
            var selectedItemTextChanged = false;
            var dataServiceMock = new Mock<IDataService>();
            var viewModel = new AddFundFlowViewModel(dataServiceMock.Object);

            viewModel.CurrentFundFlow = new FundFlow();
            viewModel.PropertyChanged += (sender, args) =>
            {
                if (args.PropertyName == "CurrentFundFlow")
                    currentFundFlowChanged = true;
                if (args.PropertyName == "SelectedItemText")
                    selectedItemTextChanged = true;
            };
            viewModel.RecentlyItemUpdateCommand.Execute(5);

            Assert.AreEqual(5, viewModel.CurrentFundFlow.ItemId);
            Assert.IsTrue(selectedItemTextChanged);
            Assert.IsTrue(currentFundFlowChanged);
        }

        [TestMethod]
        public void UpdateCurrentFundFlowUpdatesSelectedItemText()
        {
            var selectedItemTextChanged = false;
            var dataServiceMock = new Mock<IDataService>();
            var viewModel = new AddFundFlowViewModel(dataServiceMock.Object);

            viewModel.PropertyChanged += (sender, args) =>
            {
                if (args.PropertyName == "SelectedItemText")
                    selectedItemTextChanged = true;
            };
            viewModel.CurrentFundFlow = new FundFlow();

            Assert.IsTrue(selectedItemTextChanged);
        }

        [TestMethod]
        public void PropertySelectedItemTextShowsSpecialTextWhenCurrentFundFlowEmpty()
        {
            var dataServiceMock = new Mock<IDataService>();
            var viewModel = new AddFundFlowViewModel(dataServiceMock.Object);

            viewModel.CurrentFundFlow = null;
            Assert.AreEqual("Не выбрано", viewModel.SelectedItemText);

            viewModel.CurrentFundFlow = new FundFlow() {ItemId = 0};
            Assert.AreEqual("Не выбрано", viewModel.SelectedItemText);
        }

        [TestMethod]
        public void PropertySelectedItemTextShowsCurrentFundFlowItemName()
        {
            var dataServiceMock = new Mock<IDataService>();
            dataServiceMock.Setup(s => s.GetItemById(1)).Returns(new Item() {Name = "Test item"});
            var viewModel = new AddFundFlowViewModel(dataServiceMock.Object);

            viewModel.CurrentFundFlow = new FundFlow() {ItemId = 1};

            Assert.AreEqual("Test item", viewModel.SelectedItemText);
        }

        [TestMethod]
        public void CantSaveFundFlowWhenViewModelCreated()
        {
            var dataServiceMock = new Mock<IDataService>();
            var viewModel = new AddFundFlowViewModel(dataServiceMock.Object);

            var canSave = viewModel.SaveCommand.CanExecute(null);

            Assert.IsFalse(canSave);
        }

        [TestMethod]
        public void CantSaveFundFlowWithFlowTypeNone()
        {
            var dataServiceMock = new Mock<IDataService>();
            var viewModel = new AddFundFlowViewModel(dataServiceMock.Object);

            viewModel.CurrentFundFlow = new FundFlow(FlowType.None)
            {
                Amount = 1.00m, ItemId = 1, ItemName = "Test Item"
            };
            var canSave = viewModel.SaveCommand.CanExecute(null);

            Assert.IsFalse(canSave);
        }

        [TestMethod]
        public void CantSaveFundFlowWhenAmountLessOrEqualZero()
        {
            var dataServiceMock = new Mock<IDataService>();
            var viewModel = new AddFundFlowViewModel(dataServiceMock.Object);

            viewModel.CurrentFundFlow = new FundFlow(FlowType.None)
            {
                Amount = 0.00m,
                ItemId = 1,
                ItemName = "Test Item"
            };
            var canSave0 = viewModel.SaveCommand.CanExecute(null);
            viewModel.CurrentFundFlow.Amount = -5.00m;
            var canSaveMinus5 = viewModel.SaveCommand.CanExecute(null);

            Assert.IsFalse(canSave0);
            Assert.IsFalse(canSaveMinus5);
        }

        [TestMethod]
        public void CantSaveFundFlowWhenItemIdZero()
        {
            var dataServiceMock = new Mock<IDataService>();
            var viewModel = new AddFundFlowViewModel(dataServiceMock.Object);

            viewModel.CurrentFundFlow = new FundFlow(FlowType.Expense)
            {
                Amount = 5.00m,
                ItemId = 0,
                ItemName = "Test Item"
            };
            var canSave = viewModel.SaveCommand.CanExecute(null);

            Assert.IsFalse(canSave);
        }

        [TestMethod]
        public void CanSaveFundFlow()
        {
            var dataServiceMock = new Mock<IDataService>();
            var viewModel = new AddFundFlowViewModel(dataServiceMock.Object);

            viewModel.CurrentFundFlow = new FundFlow(FlowType.Expense)
            {
                Amount = 1.00m, ItemId = 1, ItemName = "Test Item"
            };
            var canSave = viewModel.SaveCommand.CanExecute(null);

            Assert.IsTrue(canSave);
        }
    }
}
